#include "Rectangle.h"
#include "menu.h"
#include "Gotoxy.h"
#include "ScreenApp.h"
#include<iostream>
using namespace std;

//c'tor with file
MyRectangle::MyRectangle( ifstream &in_file, bool binary): Shape(in_file, binary)
{
	if(binary)
	{
		in_file.read( (char*)&m_height, sizeof(int) );
		in_file.read( (char*)&m_width, sizeof(int) );
	}
	else
		in_file >> m_height >> m_width;
}

MyRectangle::MyRectangle( MyRectangle &other)
{
	m_height = other.getHeight();
	m_width = other.getWidth();
}

void MyRectangle::setShape() //recieves a rectangle from the user and inserts it into the container.
{
	cout << "Enter the top left point of the rectangle: ";
	Shape::setPoint();
	cout << "Enter Rectangle Height: ";
	cin >> m_height;
	cout << "Enter Rectangle width: ";
	cin >> m_width;

	if( m_width <= 0 || m_height <= 0)
	{
		Menu l_menu(Menu::MAIN);
		cerr << "Error! height and width must be bigger then 0";
		l_menu.choose();
	}
}

void MyRectangle::draw(char sign)
{
	int l_x = getX(), l_y = getY(), tmpX,tmpY; 
	int l_width = l_x + m_width, l_height = l_y + m_height;
	bool once = true;

	if( l_width < 0 && l_height < 0)
		return;
	//if x is negative start from left side of the screen
	if(l_x < 0)
		l_x = 0;
	//if y is negative start from top of the screen
	if(l_y < 0)
		l_y = 0;
	//save the initial value of x and y
	tmpX = l_x;
	tmpY = l_y;
	int i = 5+9;

	//width
	for(int i=0; i < 2; i++)
	{
		if( getY() < 0 && once ) //if y is negative, do only one iteration
		{
			l_y += l_height - 1; 
			once = false;
			continue;
		}
		while( l_x < l_width)
		{
			gotoxy(l_x++,l_y);
			cout << sign;
		}
		l_y += m_height - 1; //move to the second place by height
		l_x = tmpX;
	}
	if( tmpY == 0)
		l_y = tmpY;
	else
		l_y = getY() + 1;
	once = true;

	//height
	for(int i=0; i < 2; i++)
	{
		if( getX() < 0 && once) //if x is negative, do only one iteration
		{
			l_x += l_width-1; 
			once = false;
			continue;
		}
		while( l_y < l_height - 1)
		{
			gotoxy(l_x,l_y++);
			cout << sign;
		}
		l_x += m_width-1;

		if( tmpY == 0)
			l_y = tmpY;
		else
			l_y = tmpY + 1;
	}
}

void MyRectangle::drawWithHiding(char sign)//draws the rectangles on top of eachother by hiding the previous.
{
	int l_x = getX(),l_y = getY(),tmpX; 
	int l_width = l_x + m_width-1;
	int l_height;

	draw(sign);
	//if x is negative, start spaces from left side of screen
	if(l_x < 0) 
		l_x = 0;
	else
		l_x++;

	if( l_y < 0)
	{
		l_y = 0;
		l_height = m_height + getY() - 1;
	}
	else
	{
		l_y++;
		l_height = m_height - 2;
	}

	tmpX = l_x;
	
	//print the spaces inside the rectangle
	for(int i=0; i < l_height; i++)
	{
		while( l_x < l_width )
		{
			gotoxy(l_x++,l_y);
			cout << " ";
		}
		l_y++; 
		l_x = tmpX;
	}
}

bool MyRectangle::isInShape(int x, int y)
{
	bool in_rect = true;
	int l_x,l_y;

	l_x = getX();
	l_y = getY();

	if ( (x >= l_x) && (x < (l_x + m_width)) )
		if( (y >= l_y) && (y < l_y + m_height))
			return in_rect;
	
	return !in_rect;
}

Shape* MyRectangle::copyShape(const Shape* other)
{
	MyRectangle *tmp = new MyRectangle;
	*tmp = *((MyRectangle*)other);
	return tmp;
}

void MyRectangle::drawToBuffer(screen &scr)
{
	int l_x = getX(), l_y = getY(), tmpX,tmpY; 
	int l_width = l_x + m_width, l_height = l_y + m_height;
	bool once = true;

	if( l_width < 0 && l_height < 0)
		return;
	//if x is negative start from left side of the screen
	if(l_x < 0)
		l_x = 0;
	//if y is negative start from top of the screen
	if(l_y < 0)
		l_y = 0;
	//save the initial value of x and y
	tmpX = l_x;
	tmpY = l_y;

	//width
	for(int i=0; i < 2; i++)
	{
		if( getY() < 0 && once ) //if y is negative, do only one iteration
		{
			l_y += l_height - 1; 
			once = false;
			continue;
		}
		while( l_x < l_width)
			scr.changeCell(l_x++,l_y,'*');

		l_y += m_height - 1; //move to the second place by height
		l_x = tmpX;
	}
	if( tmpY == 0)
		l_y = tmpY;
	else
		l_y = getY() + 1;
	once = true;

	//height
	for(int i=0; i < 2; i++)
	{
		if( getX() < 0 && once) //if x is negative, do only one iteration
		{
			l_x += l_width-1; 
			once = false;
			continue;
		}
		while( l_y < l_height - 1)
			scr.changeCell(l_x,l_y++,'*');
		l_x += m_width - 1;

		if( tmpY == 0)
			l_y = tmpY;
		else
			l_y = tmpY + 1;
	}
}

void MyRectangle::calcShapeMove(ShapeContainer &work_cont, list<Shape*>::iterator itr, bool withTransfer)
{
	double x_shift = getShiftX();
	double y_shift = getShiftY();

	if(withTransfer)
	{
		//screen collision check
		//width
		if( x_shift > 0 && ( getX() + m_width ) >= (s_width - 1) )
			setX(0);
		else if( x_shift < 0 && getX() <= 0)
			setX(s_width - (m_width) );
		if( y_shift > 0 && (getY() + m_height ) >= s_height )
			setY(0);
		else if( getY() < 0)
			setY(s_height - m_height);
	}
	else //With Collision
	{
		//end of screen collision check
		//width
		//left
		if( x_shift < 0 && getX() <= 0 ) 
		{
			setShiftX( getShiftX() * -1 );
			setShiftXTmp( getShiftXTmp() * -1 );
		}
		//right
		else if( x_shift > 0 && ( getX() + m_width >= s_width ) )
		{
			setShiftX( getShiftX() * -1 );
			setShiftXTmp( getShiftXTmp() * -1 );
		}
		//collision in y end of screen
		//up
		if( y_shift < 0 && getY() <= 0)
		{
			setShiftY( getShiftY() * -1 );
			setShiftYTmp( getShiftYTmp() * -1 );
		}
		//down
		else if( y_shift > 0 && ( (getY() + m_height) >= s_height ) )
		{
			setShiftY( getShiftY() * -1 );
			setShiftYTmp( getShiftYTmp() * -1 );
		}
	}

	calcMoveAux(itr,work_cont,withTransfer);
}

void MyRectangle::calcMoveAux(list<Shape*>::iterator itr, ShapeContainer &work_cont, bool withTransfer)//auxillary function to calcmove
{
	double tmp;
	//x
	if(getShiftX() != 0)
	{
		setShiftXTmp(tmp = (getShiftXTmp() + getShiftX()) );

		if( abs(tmp) >= 1 )
		{
			ScreenApp scr_app;
			if(!withTransfer)
			{ 
				scr_app.rectCollisionAux(itr,work_cont);
				changeX((int)tmp);
			}
			else
				changeX((int)tmp);

			scr_app.clearNewScreen();
			scr_app.updateNewScreen(work_cont);
		
			if( tmp < 0)
				setShiftXTmp(getShiftX() + 1);
			else
				setShiftXTmp(getShiftX() - 1);
		}	
	}
	if(getShiftY() !=0 )
	{
		//y
		setShiftYTmp(tmp = (getShiftYTmp() + getShiftY()) );

		if( abs(tmp) >= 1 )
		{
			ScreenApp scr_app;
			if(!withTransfer)
			{ 
				scr_app.rectCollisionAux(itr,work_cont);
				changeY((int)tmp);
			}
			else
				changeY((int)tmp);

			scr_app.clearNewScreen();
			scr_app.updateNewScreen(work_cont);

			if( tmp < 0)
				setShiftYTmp(getShiftY() + 1);
			else
				setShiftYTmp(getShiftY() - 1);
		}
	}
}

void MyRectangle::save( ofstream &out_file, bool binary)
{
	Shape::save( out_file, binary);

	if(binary)
	{	
		out_file.write( (const char*)&m_height, sizeof(int) );
		out_file.write( (const char*)&m_width, sizeof(int) );
	}
	else
		out_file << " " << m_height << " " << m_width << endl;
		//out_file << "R " << ;
		//out_file << (*this);
		
}